--UIDungeonMgr
--create by zouyb
--关卡管理器

require "game/ui/form/dungeon/UIDungeonMain"
require "game/ui/form/combat_stat/UICombatStat"

module("UIDungeonMgr", package.seeall);

local uiLevel = nil;

local SEPERATOR_FORM_NAME = "SeperatorForm";

-- boss出场时锁屏的时间
local BOSS_LOCK_SCREEN_TIME = 7.5;

-- 地牢通关事件
EventMgr.register("UIDungeonMgr", event.DUNGEON_PASS, function()
    local dungeonId = DungeonM.getDungeonId();
    local parentId = DungeonAreaM.getParentId(dungeonId);
    if DungeonAreaM.isAllSubAreaPassed(ME.user, parentId) then
        local nextMainAreaId = DungeonAreaM.getNextMainArea(parentId);
        ME.user.dbase:setTemp("new_passed_area", parentId);
        ME.user.dbase:setTemp("new_unlock_area", nextMainAreaId);
    end
end);

-- 离开迷宫事件
EventMgr.register("UIDungeonMgr", event.LEAVE_DUNGEON, function()
    -- 离开地牢光效之类
    leaveDungeonEffect();
end);

-- 战斗结束
EventMgr.register("UIDungeonMgr", event.DUNGEON_COMBAT_END, function(combatStat)
    -- 战斗结算界面，不在这里处理
    local uiCombatStat = UICombatStat.create(combatStat);
    UIMgr.getCurrentScene():addForm(uiCombatStat);
end);

local closeTime = os.time();
-- 监听AutoFight事件
EventMgr.register("UIDungeonMgr", event.AUTO_FIGHT_MOVE, function()
    -- 1s处理一次就可以了
    if os.time() - closeTime <= 1 then
        return;
    end
    closeTime = os.time();

    -- 关闭除了主要界面以外的所有界面
    local remainForm = {"UIMainMap", "UIBottomMenu", "UITopMenu", "UIDungeonMain"};
    UIMgr.getCurrentScene():removeAllFormWithoutList(remainForm);
    UIMgr.getCurrentScene().topMenu:setLocalZOrder(UIMgr.TOP_MENU_ZORDER);
end);

EventMgr.register("UIDungeonMgr", event.AUTO_FIGHT_LEAVE, function()
    -- 离开
    leaveDungeon();
end);

EventMgr.register("UIDungeonMgr", event.AUTO_FIGHT_PAUSE, function()
    -- 暂离
    pauseDungeon();
end);



-- 获取地牢需要加载的美术资源
function getCurDungeonResList(data)
    local resList = {};
    local csbList = {};

    -- 界面合图
    table.insert(resList, "images/ui/level.png");

    local parentId;
    local style;
    -- 获取风格和区域ID
    if UnrealDungeonM.isInUnreal() then
        local unrealId = UnrealDungeonM.getUnrealId();
        parentId = UnrealDungeonM.query(unrealId, "scene_style");
        style = DungeonAreaM.query(parentId, "style");
    else
        local dungeonId = DungeonM.getDungeonId();
        parentId  = DungeonAreaM.getParentId(dungeonId);
        style = DungeonAreaM.query(dungeonId, "style");
    end

    -- 如果没有配置上下底图标，默认使用关卡编号
    local topBottomIcon = DungeonAreaM.query(parentId, "top_bottom_icon");
    if topBottomIcon == "" or topBottomIcon == nil then
        topBottomIcon = parentId;
    end

    -- 上下底
    table.insert(resList, getDungeonTopIconPath(topBottomIcon));
    table.insert(resList, getDungeonBottomIconPath(topBottomIcon));

    -- 风格
    table.insert(resList, "images/cover/" .. style .. ".png");

    -- 地砖阴影
    table.insert(resList, "images/ui/common/brick_shadow.png");

    -- 如果是夹层场景
    if UnrealDungeonM.isInUnreal() then
        -- 获取场景资源
        local unrealId = UnrealDungeonM.getUnrealId();
        local sceneId = UnrealDungeonM.query(unrealId, "scene_id");
        local resources = UnrealDungeonM.getResourceBySceneId(sceneId);
        if type(resources) == 'table'then
            for _, id in pairs(resources) do
                local resCfg = UnrealDungeonM.queryResource(id);
                local iconPath = getUnrealSceneIconPath(resCfg["icon"]);
                table.insert(resList, iconPath);
            end
        end
    end

    -- 门、障碍、钥匙
    table.insert(resList, getLevelItemIconPath("door"));
    table.insert(resList, getLevelItemIconPath("block"));
    table.insert(resList, getLevelItemIconPath("key"));
    table.insert(resList, getLevelItemIconPath("shadow"));

    -- 怪物, TODO其他待添加
    for i = 1, GRID_ROW_NUM do
        for j = 1, GRID_COL_NUM do
            local index = (i - 1) * GRID_COL_NUM + j;
            local gridData = data[index];
            local gridType = gridData.type;
            if gridType == GRID_TYPE_MONSTER
                or gridType == GRID_TYPE_BOX
                or gridType == GRID_TYPE_BOSS then
                local classId = gridData.monster:query("class_id");
                local animName = MonsterM.query(classId, "normal_anima");
                local dieAnim =  MonsterM.query(classId, "die_anima");

                local type = MonsterM.query(classId, "monster_type");
                if type ~= MONSTER_TYPE_SLIME and type ~= MONSTER_TYPE_AUDIENCE then
                    table.insert(resList, "images/animation/" .. animName .. ".png");
                    table.insert(resList, "images/animation/" .. dieAnim .. ".png");
                    table.insert(csbList, "animation/" .. animName .. ".csb");
                end
            elseif gridType == GRID_TYPE_ITEM then
                local iconPath;
                if gridData.bonus and gridData.bonus[1] == 1 then
                    local itemId = gridData.bonus[2];
                    local fileName = ItemM.query(itemId, "icon");
                    iconPath = getItemIconPath(fileName);

                    local icon = gridData.icon;

                    if icon ~= nil then
                        if type(icon) == "string" then
                            iconPath = getLevelItemIconPath(icon);
                        elseif type(icon) == "number" then
                            iconPath = getItemIconPath(icon);
                        end
                    end

                    table.insert(resList, iconPath);
                elseif gridData.bonus and gridData.bonus[1] == 2 then
                    -- 属性奖励
                    local icon = gridData.icon;
                    if not icon then
                        icon = FieldsM.query(gridData.bonus[2], "icon");
                    end
                    iconPath = getLevelItemIconPath(icon);
                    table.insert(resList, iconPath);
                end
            else
                -- 如果是配置在building_view表中的建筑，也要提前预加载
                local class = gridData.class;
                local icon = BuildingBonusM.queryBuildingView(class, "icon");
                if type(icon) == "string" and icon ~= "" then
                    local iconPath = getLevelItemIconPath(icon);
                    if table.indexOf(resList, iconPath) == -1 then
                        table.insert(resList, iconPath);
                    end
                end
            end
        end
    end

    -- 光效：道具出现
    table.insert(resList, "images/effects/effect_31.png");
    -- 光效：打开格子
    table.insert(resList, "images/animation/open_block.png");
    -- 光效：怪物出现
    table.insert(resList, "images/effect_anim/nc_monster_appear.png");

    -- 当前所用的冈布奥动作
    local hero = ME.user:getActivePet();
    local modelId = hero:getModelId();
    local animName = PetM.queryModel(modelId, "animation");
    table.insert(resList, "images/slime_animation/" .. animName .. ".png");
    table.insert(csbList, "slime_animation/" .. animName .. ".csb");

    -- 获取其他预加载资源
    local resOtherList, csbOtherList = DungeonM.getAsyncDiffResByDungeon(parentId);
    if nil ~= resOtherList and #resOtherList > 0 then
        resList = table.add(resList, resOtherList);
    end
    if nil ~= csbOtherList and #csbOtherList > 0 then
        csbList = table.add(csbList, csbOtherList);
    end

    if DEBUG_MODE == 1 then
        for _, path in pairs(resList) do
            -- 异步加载文件前，先检查文件是否存在
            if not cc.FileUtils:getInstance():isFileExist(path) then
               error("文件异步加载失败，请检查, path:" .. path);
            end
        end
    end

    return resList, csbList;
end

-- 获取当前关卡界面
function getCurLevel()
    return uiLevel;
end

-- 清除当前关卡
function clearCurLevel()
    uiLevel = nil;
end

-- 进入当前关卡
function startDungeon(data, layer)
    math.randomseed(os.time());

    -- 增加一层隔离窗口，隔离地牢界面和主地图界面
    showBlackForm(SEPERATOR_FORM_NAME);

    GameAnalytics.startLevel("level_"..DungeonM.getDungeonId().."_"..layer);

    -- -- 判断是否默认开启所有的格子
    -- if DungeonM.isOpenAllGridsWhenStart() then
    --     DungeonM.openAllGrids();
    -- end

    if UIMgr:getCurrentScene():isOpen("UICommunicating") then
        closeCommunicatingForm();
    end

    -- 清理下资源
    UIMgr.clearUnusedTextures();

    -- 获取需要加载的美术资源
    local resList, csbList = getCurDungeonResList(data);

    -- 是否显示游戏小贴士
    local showTips = true;
    if uiLevel ~= nil then
        showTips = false;
    end

    -- 异步加载，加载完成后再初始化地牢界面，同时显示"加载中"
    showCommunicatingForm(getLocStr("loading"), showTips, false, nil, "enter_dungeon");
    for _, csbPath in pairs(csbList) do
        cc.CSLoader:getInstance():loadCsbAsync(csbPath);
    end

    loadImagesAsync(resList, function()
        if uiLevel ~= nil then
            UIMgr.getCurrentScene():removeFormByName("UIDungeonMain");
            uiLevel = nil;
        end

        -- 如果不是在迷宫中
        if DungeonM.getState() ~= DUNGEON_GAMING then
            return;
        end

        -- 初始化地牢界面
        uiLevel = UIDungeonMain.create(data, layer);
        UIMgr.getCurrentScene():addForm(uiLevel);

        -- 关闭"加载中"提示
        local delay = 0;
        if UIMgr:getCurrentScene():isOpen("UICommunicating") then
            delay = closeCommunicatingForm();
        end

        -- 如果有遗产可领取，弹出提示（暂离状态回来无需提示）
        if DungeonLegacyM.hasLeagacy() and
           not DungeonM.isPause() then
            local function callback()
                -- 弹出任务提示
                showHint2(getLocStr("slime_legacy_title"), getLocStr("legacy_search_tip"));
            end
            performWithDelay(uiLevel, callback, 0.5);
        end

        -- BOSS层需要播放出场光效
        local allGrids = UIDungeonMgr.getCurLevel():getAllGrids();
        local cleared = DungeonServiceM.isMonsterClear();
        local value = ME.user.monsterClearedTip;
        if cleared and type(value) == "number" then
            -- 显示清怪回调
            UIDungeonMgr.getCurLevel():monsterClearFunc(value);
        else
            -- 清除字段
            ME.user.monsterClearedTip = nil;
        end

        local isBossLayer = false;
        for _, grid in pairs(allGrids) do
            -- 清怪回调
            if cleared then
                grid:onAllMonsterKilled();
            end

            -- 倒计时
            grid:updateCountDown();
            -- 检查时间停止暂停动作
            grid:checkTimePause();
            -- 更换模型
            grid:changeMonsterModel();

            -- 特殊入场形式
            grid:specialEnterEffect(delay);

            if grid.gridData.type == GRID_TYPE_BOSS then
                isBossLayer = true;

                -- 锁屏下，免得玩家继续操作
                uiLevel:lockScreen(BOSS_LOCK_SCREEN_TIME);

                -- 播放boss出场动画
                if type(grid.gridData.boss_enter_effect_pos) == "number" then
                    playBossAppearEffect(grid.gridData.boss_enter_effect_pos);
                else
                    playBossAppearEffect();
                end

                -- 需要扣除体力，设置一个临时变量
                ME.user.dbase:setTemp("bossLayerCostLife", true);
                break;
            end
        end

        -- 检查神龙夹层发言
        local unrealId = ME.user.dbase:queryTemp("startUnrealDungeon");
        if unrealId then
            local dbase = UnrealDungeonM.query(unrealId, "dbase");
            if type(dbase) == "table" and type(dbase["random_talk_grids"]) == 'table' then
                -- 触发随机发言
                local randPosList = dbase["random_talk_grids"];
                UIDungeonMgr.getCurLevel():doRandTalk(randPosList);
            end

            -- 勇者斗恶龙-拉达多姆夹层
            if unrealId == 22 then
                -- 触发侍卫发言，随机挑选一个位置
                local posList = { 27, 29, };
                local index = math.random(#posList);
                local pos = posList[index];
                local grid = UIDungeonMgr.getCurLevel().grids[pos];
                local function doGuardsTalk()
                    grid:doGuardsTalk();
                end
                performWithDelay(grid, doGuardsTalk, 1.0);

                -- 如果救出公主后，公主还没出现，尝试触发国王的发言
                if BraveVSDragonM.hasRescuedPrincess() and not BraveVSDragonM.hasPrincessAppeared() then
                    local kingPos = 9;
                    local grid = UIDungeonMgr.getCurLevel().grids[kingPos];
                    grid:doKingTalkRescue();
                end
            end

            -- 检查创世之门夹层发言
            CreationGateM.checkRoleTalk();

            -- 删除临时变量
            ME.user.dbase:deleteTemp("startUnrealDungeon");
        end

        -- 进入洞窟发言
        local instanceId = DungeonInstanceM.getCurrentInstanceId();
        if instanceId then
            if instanceId == 34 then
                -- 进入多姆多拉触发神官对话
                if not BraveVSDragonM.hasTalkedWithRole(GRID_TYPE_PRIEST, 1) then
                    -- 触发对话
                    DungeonActionM.go("talk_with_brave_role", 2, 1);

                    -- 触发对话
                    startDialogueTemplate("priest_talk1");
                    return;
                end
            end
        end

        -- 触发自动施法属性
        -- 注：正常情况，这段代码应该放在逻辑层进入下一层的回调中。
        -- 之所以放在这里，是为了满足客户端播放序列的需求，必须等UI层准备完毕才播放
        local function triggerProp()
            if DungeonActionM.go("prop_auto_cast2") then
                EventMgr.fire(event.PLAYER_MOVE);
            end
        end

        -- 如果是boss层，必须等boss出场动画播放完才触发
        if isBossLayer then
            performWithDelay(uiLevel, triggerProp, BOSS_LOCK_SCREEN_TIME - 0.5);
        else
            performWithDelay(uiLevel, triggerProp, 0.5);
        end
    end);
end

-- 离开地牢
function leaveDungeon()
    -- 离开迷宫就行了
    DungeonActionM.go("leave_dungeon")
end

-- 仅仅是和光效有关
function leaveDungeonEffect()
    -- 关闭当前界面
    UIMgr.getCurrentScene():removeFormByName("UIDungeonInfo");

    -- 关闭复活界面
    UIMgr.getCurrentScene():removeFormByName("UIDungeonRevive");

    -- 关闭合成界面
    UIMgr.getCurrentScene():removeFormByName("UIItemCompound");

    -- 移除所有UIDungeonMain界面的监听回调消息
    EventMgr.removeAll("UIDungeonMain");

    -- 删除隔离窗口
    hideBlackForm(SEPERATOR_FORM_NAME);

    if UIDungeonMgr.getCurLevel() then
        -- 停止所有预警特效
        UIDungeonMgr.getCurLevel():stopAllAlertEffect();

        -- 移除effectParent下面的所有子节点
        local effectParent = getCurLevel():getEffectParent();
        if effectParent then
            effectParent:removeAllChildren();
        end
    end

    if UIMgr.getCurrentScene().mainMap ~= nil then
        UIMgr.getCurrentScene().mainMap:updateMsgReminderUI();
        UIMgr.getCurrentScene().mainMap:setNormalColor();
        UIMgr.getCurrentScene().bottomMenu:setNormalColor();
        UIMgr.getCurrentScene().topMenu:setNormalColor();
    end
end

-- 暂离地牢
function pauseDungeon()
    if DungeonInstanceM.isInInstance() then
        -- 副本中无法暂离
        return;
    end

    -- 离开
    DungeonActionM.go("pause_dungeon");

    -- 关闭当前界面
    UIMgr.getCurrentScene():removeFormByName("UIDungeonInfo");

    -- 关闭地牢主界面
    UIMgr.getCurrentScene():removeFormByName("UIDungeonMain");
    clearCurLevel();

    UIMgr.getCurrentScene():removeFormByName("UIDungeonTopMenu");

    -- 删除隔离窗口
    hideBlackForm(SEPERATOR_FORM_NAME);

    if UIMgr.getCurrentScene().mainMap ~= nil then
        UIMgr.getCurrentScene().mainMap:updateMsgReminderUI();

        UIMgr.getCurrentScene().mainMap:checkPauseState();
        UIMgr.getCurrentScene().bottomMenu:checkPauseState();
        UIMgr.getCurrentScene().topMenu:checkPauseState();
    end
end
